package edu.tgc.aop;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.abyss.utils.JsonUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AjaxLoginAdvise {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
    private RequestCache requestCache = new HttpSessionRequestCache();

    protected final void clearAuthenticationAttributes(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session == null) {
            return;
        }
        session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
    }

    @Around(value = "execution(* org.springframework.security.web.AuthenticationEntryPoint.commence(..)) and args(request,response,authException)")
    public Object commence(ProceedingJoinPoint joinPoint, HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws Throwable {
        if ("XMLHttpRequest".equalsIgnoreCase(request.getHeader("X-Requested-With"))) {
            response.setStatus(HttpStatus.FORBIDDEN.value());
            response.setHeader("sessionStatus", "requireLogin");
            Map<String, Object> json = new HashMap<>();
            json.put("message", authException.getMessage());
            json.put("sessionStatus", "requireLogin");
            json.put("rows", new ArrayList<String>());
            response.getWriter().write(JsonUtils.writeValue(json));
            this.logger.info("ajax需要登录");
            return null;
        } else {
            return joinPoint.proceed();
        }
    }

    @Around(value = "execution(* org.springframework.security.web.access.AccessDeniedHandler.handle(..)) and args(request,response,accessDeniedException)")
    public Object denied(ProceedingJoinPoint joinPoint, HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws Throwable {
        if ("XMLHttpRequest".equalsIgnoreCase(request.getHeader("X-Requested-With"))) {
            response.setStatus(HttpStatus.FORBIDDEN.value());
            response.setHeader("sessionStatus", "requireLogin");
            Map<String, Object> json = new HashMap<>();
            json.put("message", accessDeniedException.getMessage());
            json.put("sessionStatus", "requireLogin");
            json.put("rows", new ArrayList<String>());
            response.getWriter().write(JsonUtils.writeValue(json));
            this.logger.info("ajax缺少权限");
            return null;
        } else {
            return joinPoint.proceed();
        }
    }

    @Around(value = "execution(* org.springframework.security.web.authentication.AuthenticationFailureHandler.onAuthenticationFailure(..)) and args(request,response,exception)")
    public Object failed(ProceedingJoinPoint joinPoint, HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws Throwable {
        if ("XMLHttpRequest".equalsIgnoreCase(request.getHeader("X-Requested-With"))) {
            // TODO ajax返回值
            response.setStatus(HttpStatus.FORBIDDEN.value());
            response.setHeader("sessionStatus", "requireLogin");
            Map<String, Object> json = new HashMap<>();
            json.put("message", exception.getMessage());
            json.put("sessionStatus", "requireLogin");
            json.put("rows", new ArrayList<String>());
            response.getWriter().write(JsonUtils.writeValue(json));
            this.logger.info("ajax登陆失败");
            return null;
        } else {
            return joinPoint.proceed();
        }
    }

    @Around(value = "execution(* org.springframework.security.web.authentication.AuthenticationSuccessHandler.onAuthenticationSuccess(..)) and args(request,response,authentication)")
    public Object success(ProceedingJoinPoint joinPoint, HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws Throwable {
        if ("XMLHttpRequest".equalsIgnoreCase(request.getHeader("X-Requested-With"))) {
            response.setHeader("requireLogin", "false");
            response.getWriter().write("{登陆成功}");
            this.logger.info("ajax登陆成功");
            SavedRequest savedRequest = this.requestCache.getRequest(request, response);
            if (savedRequest != null) {
                this.requestCache.removeRequest(request, response);
            }
            clearAuthenticationAttributes(request);
            return null;
        } else {
            return joinPoint.proceed();
        }
    }

}
